import store from "@/store";
import {
	ab2hex,
	hex2int,
	hex2ab,
	hex2float,
	stringToHex,
	hexToString,
    formReceiveData
} from '@/utils/utils.js'
import {
    ooo1,
    ooo8
} from '@/api/bleApi.js'
import { API_URL } from '@/utils/env.js'
const server_url = API_URL
// 获取校验和
function chk8xor(hexarr) {
	var bcc = 0;
	var xor = 0;
	for (var i = 0; i < hexarr.length; i++) {
		var hexint = parseInt(hexarr[i], 16);
		if (i == 0) {
			xor = hexint;
		} else {
			bcc = xor ^ hexint;
			xor = bcc;
		}
	}
	return fillZero(bcc.toString(16), 2)
}

//字符串长度判断不足填充0
function fillZero(num, n) {
	var len = num.toString().length;
	while (len < n) {
		num = "0" + num;
		len++;
	}
	return num;
}


// 创建回复数据
function createReply(oData = '', type, time) {
	// 获取标识位及消息头的数据
	let info = createBody(type, oData, time)
	let body = info.data
	let pre = createHead(type, info.length)
	let ackData = [...pre, ...body]
	// console.log(ackData)
	// 获取校验和
	let checksum = chk8xor(ackData)
	let newArr
	let newAckData = new Array()
	// 将需要转义的数据提取
	for (var i = 0, j = 0; i < ackData.length; i++, j++) {
		if (ackData[i] == '7e' || ackData[i] == '7E') {
			newAckData[j] = '7d'
			newAckData[j + 1] = '02'
			j++;
		} else if (ackData[i] == '7d' || ackData[i] == '7D') {
			newAckData[j] = '7d'
			newAckData[j + 1] = '01'
			j++;
		} else {
			newAckData[j] = ackData[i]
		}
	}
	// console.log(newAckData)
	if (checksum == '7d') {
		newArr = ['7e', ...newAckData, '7d', '01', '7e']
	} else if (checksum == '7e') {
		newArr = ['7e', ...newAckData, '7d', '02', '7e']
	} else {
		newArr = ['7e', ...newAckData, checksum, '7e']
	}

	let content = '';

	for (let i = 0; i < newArr.length; i++) {
		content += newArr[i];
	}
	return content.toLocaleUpperCase();
}
// 创建消息头及标识位
/*
	oData: 原始数据
	type: 表示要回复的类型
*/
function createHead(type, length) {
	let ackArray = new Array();
	if (type == 'query') { // 查询仪器硬件固件版本数据
		ackArray[0] = '8b' // 回复消息类型
	} else if (type == 'now') {
		ackArray[0] = '8c' // 回复消息类型
	} else if (type == 'start') {
		ackArray[0] = '8d' // 回复消息类型
	} else if (type == 'end') {
		ackArray[0] = '8d' // 回复消息类型
	} else if (type == 'response') {
		ackArray[0] = '88' // 回复消息类型
	} else if (type == 'inquire') {
		ackArray[0] = '8e' // 回复消息类型
	} else if (type == 'upgrade') {
		ackArray[0] = '8f' // 回复消息类型
	} else if (type == 'sendUpgrade') {
		ackArray[0] = '90' // 回复消息类型
	} else if (type == 'stopUpgrade') {
		ackArray[0] = '91' // 回复消息类型
	}
	ackArray[1] = '00' // 回复的消息体长度
	ackArray[2] = length // 回复的消息体长度
	ackArray[3] = store.state.ble.defaultInfo.version ? store.state.ble.defaultInfo.version : '01' // 协议版本号为原始数据中携带的数据
	let num;
	let serial = uni.getStorageSync('serial') + 1
	uni.setStorageSync('serial', serial)
	serial = serial.toString(16).toLocaleUpperCase()
	if (serial.length % 2 == 1) {
		num = '0' + serial
	} else {
		num = serial
	}
	if (num.length == 2) {
		num = '00' + num
	}
	ackArray[4] = num.substring(0, 2) // 消息流水号为自连接后自动生成递增的数字
	ackArray[5] = num.substring(2, 4) // 消息流水号为自连接后自动生成递增的数字
	return ackArray
}

// 创建消息体
function createBody(type, sNum, time) { // sNum: 传输的数据
	let ackArray = new Array();
	if (type == 'now') {
		ackArray[0] = sNum.substring(10, 12) // 应答流水号为原始数据中携带的数据
		ackArray[1] = sNum.substring(12, 14) // 应答流水号为原始数据中携带的数据
		ackArray[2] = '00' // 回复的结果
	} else if (type == 'start') {
		ackArray[0] = '01'
		let hexStr = time.toString(16)
		if (hexStr.length < 2) {
			hexStr = '0' + hexStr
		}
		ackArray[1] = hexStr
	} else if (type == 'end') {
		ackArray[0] = '02'
	} else if (type == 'response') { // 通讯应答
		ackArray[0] = sNum.substring(10, 12) // 应答流水号为原始数据中携带的数据
		ackArray[1] = sNum.substring(12, 14) // 应答流水号为原始数据中携带的数据
		ackArray[2] = '00'
		ackArray[3] = '01' // 回复的结果
	} else if (type == 'inquire') { // 查询仪器漏传或丢失数据
		let i_len = sNum.length / 3
		i_len = i_len.toString(16).length < 2 ? `0${i_len.toString(16)}` : i_len.toString(16)
		ackArray = [i_len, ...sNum]
	} else if (type == 'upgrade') { // 下发终端升级通知
		// 将字符串硬件固件版本号转换为十六进制并将数据每隔一个字节转换为数组
		let hwVersionStr = stringToHex(sNum.HwVersion)
		let hwVersionArr = hwVersionStr.split('').filter(function(value, index) {
			return index % 2 === 0;
		}).map(function(char, index) {
			return hwVersionStr.substr(index * 2, 2);
		});
		let fwVersionStr = stringToHex(sNum.FwVersion)
		let fwVersionArr = fwVersionStr.split('').filter(function(value, index) {
			return index % 2 === 0;
		}).map(function(char, index) {
			return fwVersionStr.substr(index * 2, 2);
		});
		let hvLen = hwVersionArr.length
		let fvLen = fwVersionArr.length
		hvLen = hvLen.toString(16).length < 2 ? `0${hvLen.toString(16)}` : hvLen.toString(16)
		fvLen = fvLen.toString(16).length < 2 ? `0${fvLen.toString(16)}` : fvLen.toString(16)
		let size = sNum.ImageSize.toString(16)
		if (size.length == 4) {
			size = '0000' + size
		} else if (size.length == 5) {
			size = '000' + size
		} else if (size.length == 6) {
			size = '00' + size
		} else if (size.length == 7) {
			size = '0' + size
		}
		let _SIZE = size.split('').filter(function(value, index) {
			return index % 2 === 0;
		}).map(function(char, index) {
			return size.substr(index * 2, 2);
		});
		let crc = sNum.ImageCRC.toString(16)
		if (crc.length == 3) {
			crc = '0' + crc
		} else if (crc.length == 2) {
			crc = '00' + crc
		}
		let CRC = crc.split('').filter(function(value, index) {
			return index % 2 === 0;
		}).map(function(char, index) {
			return crc.substr(index * 2, 2);
		});
		ackArray = ['00', hvLen, ...hwVersionArr, fvLen, ...fwVersionArr, ..._SIZE, ...CRC]
	} else if (type == 'sendUpgrade') { // 发送固件升级数据包
		let dataLen = sNum.length
		dataLen = dataLen.toString(16).length < 2 ? `0${dataLen.toString(16)}` : dataLen.toString(16)
		ackArray = ['00', '00', dataLen, ...sNum]
	}
	let len = ackArray.length ? ackArray.length : 0
	len = len.toString(16)
	return {
		data: ackArray,
		length: len.length < 2 ? '0' + len : len
	}
}
const common = {
	writeInfo: {},
	mergeStr: '',
	timer: null,
	withoutSend(type, time) {
		let hexInfo = createReply('', type, time)
		this.sendDataToDevice(this.writeInfo, hexInfo)
	},
	withoutSendEnd(type) {
		let hexInfo = createReply('', type)
		this.sendDataToDevice(this.writeInfo, hexInfo)
	},
	withoutInquire(info, type) {
		let hexInfo = createReply(info, type)
		this.sendDataToDevice(this.writeInfo, hexInfo)
	},
	// 升级指令
	withoutUpgrade(info, type) {
		let hexInfo = createReply(info, type)
		this.sendDataToDevice(this.writeInfo, hexInfo)
	},
	// 查询终端参数数据指令
	withoutQuery(info, type) {
		let hexInfo = createReply(info, type)
		this.sendDataToDevice(this.writeInfo, hexInfo)
	},
	// 发送固件升级数据包指令
	withoutSendUpgrade(info, type) {
		let hexInfo = createReply(info, type)
		this.sendDataToDevice(this.writeInfo, hexInfo)
	},
	// 停止本次升级
	withoutStop(info, type) {
		let hexInfo = createReply(info, type)
		this.sendDataToDevice(this.writeInfo, hexInfo)
	},
	// 向嵌入式发送请求
	setRequest(hexInfo) {
		this.sendDataToDevice(this.writeInfo, hexInfo)
	},
	// 上传当前仪器版本信息
	uploadVersion(obj) {
		let params = {
			arithmeticVersion: obj.aVersion,
			firmwareVersion: obj.FwVersion,
			id: store.state.deviceInfo.deviceId
		}
		uni.request({
			url: `${server_url}/devicewx-level/api/v1/level/YlLevelUserDevice/updateDeviceMsg`,
			data: params,
			header: {
				"Authorization": `Bearer ${uni.getStorageSync('token')}`
			},
			method: 'POST',
			success: (result) => {
				if (result.data.code == 200) {
					console.log('上传版本信息成功', result);
				}
			}
		})
	},
	// 初始化蓝牙适配器 没用到
	myOpenBluetoothAdapter(TIMEOUT, BLEINFO) {
		let that = this
		wx.openBluetoothAdapter({
			success(BleObj) {
				console.log('BleObj', BleObj)
				store.commit('changeIsOpenBleAdapter', true)
				if (uni.$u.os() == 'android') { // 安卓系统直接连接
					store.commit('setDefaultInfo', {
						type: 1,
						data: {
							mac: BLEINFO.deviceMac,
							name: BLEINFO.bluetoothName
						}
					})
					that.createBLEConnectionFn(BLEINFO.deviceMac, BLEINFO)
				} else { // 苹果系统需要搜索uuid仪器id
					that.myStartBluetoothDevicesDiscovery(TIMEOUT, BLEINFO)
				}
			},
			fail(err) {
				console.log('BleObjerr', err)
				store.commit('changeIsOpenBleAdapter', false)
				store.commit('resetBleConnectedName')
				if (err.errMsg == 'openBluetoothAdapter:fail auth deny') {
					uni.showModal({
						title: '提示',
						content: '请先授权蓝牙权限',
						confirmColor: '#545DDE',
						success(modal_res) {
							if (modal_res.confirm) {
								wx.openSetting({
									success: (authData) => {
										if (authData.authSetting[
												'scope.bluetooth']) {
											this.myOpenBluetoothAdapter(TIMEOUT,
												BLEINFO)
										} else { // 未授权
											uni.showModal({
												title: '提示',
												content: '授权失败,您将无法使用蓝牙相关服务',
												confirmColor: '#545DDE',
												showCancel: false
											})
										}
									}
								})
							} else {
								uni.showModal({
									title: '提示',
									content: '授权失败,您将无法使用蓝牙相关服务',
									confirmColor: '#545DDE',
									showCancel: false
								})
							}
						}
					})
				} else if (err.errCode == 10001) {
					// 蓝牙适配器不可用 弹框提示
					uni.showToast({
						title: '请检查蓝牙是否可用',
						icon: 'none'
					})
				}
			},
			complete() {

			}
		})
	},
	// 开始搜寻周边仪器
	myStartBluetoothDevicesDiscovery(TIMEOUT, BLEINFO) {
		console.log('搜索连接')
		if (uni.$u.os() == 'android') {
			uni.getLocation({
				type: 'wgs84',
				fail: err => {
					console.log('getLocationfail', err);
					uni.showModal({
						title: '提示',
						content: '因系统要求,小程序绑定蓝牙仪器需获取位置信息权限,请检查手机微信是否授权位置权限或检查手机是否开启GPS功能',
						showCancel: false,
						success(modal) {
							if (modal.confirm) {
								uni.openAppAuthorizeSetting({
									fail: err => {
										uni.navigateBack()
									}
								})
							}
						}
					})
					return
				}
			});
		}
		wx.startBluetoothDevicesDiscovery({
			powerLevel: 'medium',
			allowDuplicatesKey: true,
			success: (res) => {
				store.commit('changeBleState', -2)
				this.MYonBluetoothDeviceFound(BLEINFO)
				// 十秒后未搜索到仪器显示提示
				this.timer = setTimeout(() => {
					if (store.state.ble.state !== 0) {
						wx.stopBluetoothDevicesDiscovery()
						wx.offBluetoothDeviceFound()
						store.commit('changeBleState', -5)
						store.commit('resetBleConnectedName')
					}
				}, TIMEOUT ? TIMEOUT : 10000)
			},
			fail: (err) => {
				console.log('fail', err);
				store.commit('changeBleState', -4)
				store.commit('resetBleConnectedName')
			}
		});
	},
	// 搜索仪器回调
	MYonBluetoothDeviceFound(BLEINFO) {
		let that = this
		// 监听寻找到新仪器的事件
		wx.onBluetoothDeviceFound((res) => {
			res.devices.forEach(device => {
				if (!device.localName) return // 过滤掉名称为空的仪器
				// 判断是否为本公司仪器标识
				if (device.localName.startsWith('ANT') && device.advertisData) {
					// console.log('search', JSON.stringify(res.devices))
					if (BLEINFO.bluetoothName == device.localName) {
						console.log('device', device)
						clearTimeout(this.timer)
						wx.stopBluetoothDevicesDiscovery()
						// 保存仪器原始mac地址   ios端因获取的是uuid 所以跟嵌软沟通将原始mac保留在广播数据里了
						let mac = ''
						if (uni.$u.os() == 'ios') {
							let data = ab2hex(device.advertisData)
							for (let i = 0; i < data.length; i++) {
								mac += data[i];
								if (i % 2 === 1 && i != data.length - 1) mac += ':';
							}
						} else {
							mac = device.deviceId
						}
						store.commit('setDefaultInfo', {
							type: 1,
							data: {
								mac,
								name: device.localName
							}
						})
						that.createBLEConnectionFn(device.deviceId, BLEINFO)
					}
				}
			})
		})
	},
	// 建立连接低功耗蓝牙仪器
	createBLEConnectionFn(deviceId, BLEINFO) {
		let _self = this
		if (store.state.ble.state == -3) return
		store.commit('changeBleState', -3)
		wx.createBLEConnection({
			deviceId,
			timeout: 20000,
			success: (res) => {
				console.log('createBLEConnectionFn', res)
				if (uni.$u.os() == 'android') {
					wx.getBLEMTU({
						deviceId,
						success: (res) => {
							console.log(res)
							wx.onBLEMTUChange(function(res1) {
								console.log('bluetooth mtu is', res1.mtu)
							})
							wx.setBLEMTU({
								deviceId,
								mtu: 300,
								success: (resSet) => {
									console.log('setBLEMTU', resSet)
								},
								fail: (errSet) => {
									console.log('setBLEMTUfail', errSet)
								}
							})
						}
					})

				}
				store.commit('changeBleState', 0)
				store.commit('resetBleConnectedName')
				store.commit('setDevId', deviceId)
				store.commit('setDeviceInfo', BLEINFO)
				uni.setStorageSync('serial', 0)
				this.onBLEConnectionStateChange(deviceId);
				this.getBLEDeviceServices(deviceId);
			},
			fail: (err) => {
				console.log('connect fail', err);
				if (err.errMsg.indexOf('time out') == -1) {
					store.commit('changeBleState', -4)
				}else if(err.errno== '1509007'){ // 仪器已经被连接，小程序意外断开，仪器没有断开连接导致问题
                    uni.showModal({
                        title: '提示',
                        content: '连接失败，请重启仪器再次连接。',
                        confirmColor: '#545DDE',
                        showCancel: false,
                        success (modal) {
					        store.commit('changeBleState', -5)
                        }
                    })
                }
                else {
					store.commit('changeBleState', -5)
				}
				store.commit('resetBleConnectedName')
			}
		})
	},
	onBLEConnectionStateChange(deviceId) {
		wx.onBLEConnectionStateChange((res) => {
			if (!res.connected) {
				wx.offBLEConnectionStateChange()
				wx.offBLECharacteristicValueChange()
				console.log('监听断开')
				store.commit('reset')
			}
		});
	},
	// 获取仪器的所有主服务
	getBLEDeviceServices(deviceId) {
		setTimeout(() => {
			wx.getBLEDeviceServices({
				deviceId,
				success: (res) => {
					console.log('getBLEDeviceServices success', res);
					for (let i = 0; i < res.services.length; i++) {
						// console.log('res.services[' + i + '].isPrimary-->' + res.services[i]
						// 	.isPrimary);
						// console.log('res.services[' + i + '].uuid-->' + res.services[i].uuid);
						let serviceUUID = res.services[i].uuid;
						if ('0000FEE7-0000-1000-8000-00805F9B34FB' == serviceUUID) {
							this.getBLEDeviceCharacteristics(deviceId, serviceUUID, );
							return;
						}
					}
				},
				fail: (err) => {
					console.log('getBLEDeviceServices fail -->' + JSON.stringify(err));
				}
			});
		}, 800)

	},
	// 获取蓝牙仪器某个服务中所有特征值
	getBLEDeviceCharacteristics(deviceId, serviceId) {
		wx.getBLEDeviceCharacteristics({
			deviceId,
			serviceId,
			success: (res) => {
				// console.log('getBLEDeviceCharacteristics success', res.characteristics);
				res.characteristics.forEach(item => {
					if (item.properties.write) {
						// console.log('write-->' + serviceId + ';' + item.uuid);
					}

					if (item.properties.notify || item.properties.indicate) {
						// console.log('notify-->' + serviceId + ';' + item.uuid);
						let characteristicId = item.uuid
						this.openNotifyBLECharacteristicValueChange(deviceId, serviceId,
							characteristicId)
					}
				})
			},
			fail(res) {
				console.error('getBLEDeviceCharacteristics', res);
			}
		});
	},
	// 开启特征值监听
	openNotifyBLECharacteristicValueChange(deviceId, serviceId, characteristicId) {
		let that = this
		wx.notifyBLECharacteristicValueChange({
			deviceId,
			serviceId,
			characteristicId,
			state: true,
			success: () => {
				console.log('开始监听')
				this.writeInfo = {
					deviceId,
					serviceId,
					characteristicId
				}
		        uni.$emit('setRequest')
                // 电量跟版本号获取
                ooo1({type:'0001'}).then((res) => {
                    let battery = res.data[0]
                    let version = res.data[1]
                    let FwInfo = {
                        FwId:res.data[2],
                        FwVersion:'',
                        HwVersion:'',
                        aVersion:'',
                    }
                    res.data.forEach((item, index)=>{
                        if (index>2) {
                            FwInfo.FwVersion=(FwInfo.FwVersion+item).replace(/\u0000/g, '')
                        }
                    })
                    store.commit('setDefaultInfo', {
                            type: 2,
                            data: {
                                battery: battery,
                                version: version
                            }
                        })
                    store.commit('setVersionInfo', FwInfo)
                    this.uploadVersion(FwInfo)
                    ooo8()
                })
				wx.onBLECharacteristicValueChange((characteristic) => {
					var receiveData = ab2hex(characteristic.value);
                    // 获取命令码
                    let commandCode = receiveData.substring(0, 8) 
                    // 获取流水号
                    let runCode = receiveData.substring(8, 12) 
                    if ( commandCode == 'aa558006' || commandCode == 'aa558007' || commandCode == 'aa55800d' || commandCode == 'aa55800e') {
                        let resData = {
                            runCode:hex2int(runCode),
                            code:commandCode,
                            data:formReceiveData(receiveData,'crc16')
                        }
                        console.log("%c Line:310 🍢 res", "color:#fca650", JSON.stringify(resData));
                        uni.$emit('pendingData',resData)
                    }else if ( commandCode == 'aa558005'){
                        let resData = {
                            runCode:hex2int(runCode),
                            code:commandCode,
                            data:formReceiveData(receiveData,'')
                        }
                        uni.$emit('pendingData',resData)
                    }else if(commandCode == 'aa550010' ){
                        that.setRequest('aa5580100001000070B1')
                    }
                    else{
                        uni.$emit('response',receiveData)
                    }
					console.log('onBLECharacteristicValueChange-->' + receiveData);
				});
			}
		});
	},
	// 将要发送的数据转换成buffer格式并发送(写入)数据
	sendDataToDevice({
		deviceId,
		serviceId,
		characteristicId
	}, hex) {
		console.log('sendDataToDevice-->' + hex);
		let buffer = hex2ab(hex);
		setTimeout(function() {
			wx.writeBLECharacteristicValue({
				deviceId,
				serviceId,
				characteristicId,
				value: buffer,
				success(res) {
					// console.log('writeBLECharacteristicValue success', res);
				},
				fail(err) {
					console.log('writeBLECharacteristicValue failue', err);
				}
			});
		}, 500);
	}
}
module.exports = {
	common
}